package com.gitee.zhanyao.common.util;


import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Security;
import java.util.Base64;

/**
 * AES 加解密工具类
 * AES 的区块长度固定为 128 比特，密钥长度则可以是 128，192 或 256 比特；而Rijndael使用的密钥和区块长度可以是32位的整数倍，以128位为下限，256比特为上限。包括AES-ECB,AES-CBC,AES-CTR,AES-OFB,AES-CFB
 * 例：AES/CBC/PKCS5Padding，组成说明："算法/模式/补码方式"
 * 在线测试工具：http://tool.chacuo.net/cryptaes
 *
 * @author zhanyao
 */
public class AESUtil {

    /**
     * 加密
     *
     * @param src
     * @param key
     * @return
     * @throws Exception
     */
    public static String encrypt(String src, String key) throws Exception {
        if (key == null || key.length() != 16) {
            throw new Exception("key不满足条件");
        }
        byte[] raw = key.getBytes(StandardCharsets.UTF_8);
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(src.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encrypted);
    }

    /**
     * 加密
     * <p>
     * 算法/模式/补码方式：AES/ECB/PKCS7Padding
     * <p>
     * See <a href="https://blog.csdn.net/xiaoyi52/article/details/79645301">关于“Cannot find any provider supporting AES/ECB/PKCS7Padding”问题的解决方案</a>
     *
     * @param src
     * @param key
     * @param iv
     * @return
     * @throws Exception
     */
    public static String encrypt(String src, String key, String iv) throws Exception {
        if (key == null || key.length() != 16) {
            throw new Exception("key不满足条件");
        }
        Security.addProvider(new BouncyCastleProvider());
        byte[] raw = key.getBytes(StandardCharsets.UTF_8);
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES", "BC");
        byte[] ivBytes = iv.getBytes(StandardCharsets.UTF_8);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivParameterSpec);
        byte[] encrypted = cipher.doFinal(src.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encrypted);
    }

    /**
     * 解密
     *
     * @param src
     * @param key
     * @return
     * @throws Exception
     */
    public static String decrypt(String src, String key) throws Exception {
        if (key == null || key.length() != 16) {
            throw new Exception("key不满足条件");
        }
        byte[] raw = key.getBytes();
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec);
        byte[] encrypted1 = Base64.getDecoder().decode(src);
        byte[] original = cipher.doFinal(encrypted1);
        return new String(original);
    }

    /**
     * 解密
     * 算法/模式/补码方式：AES/ECB/PKCS7Padding
     *
     * @param src
     * @param key
     * @param iv
     * @return
     * @throws Exception
     */
    public static String decrypt(String src, String key, String iv) throws Exception {
        if (key == null || key.length() != 16) {
            throw new Exception("key不满足条件");
        }
        Security.addProvider(new BouncyCastleProvider());
        byte[] raw = key.getBytes(StandardCharsets.UTF_8);
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES", "BC");
        byte[] ivBytes = iv.getBytes(StandardCharsets.UTF_8);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivParameterSpec);
        byte[] encrypted1 = Base64.getDecoder().decode(src);
        byte[] original = cipher.doFinal(encrypted1);
        return new String(original);
    }

}
